package model;

import frame.GamePanel;
import type.Buff;
import type.Direction;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;

import static constant.MapElements.*;

public class Snake implements Runnable {
    public GamePanel panel; // 所属面板，主要用于获取 panel 中的 map 数组
    public int bodyRow[] = new int[600]; // 蛇的行坐标, body[0]表示蛇身行坐标
    public int bodyCol[] = new int[600]; // 蛇的列坐标, bodyX[0]表示蛇头列坐标

    public Direction direction = Direction.UP; // 蛇头方向
    public int length; // 蛇的长度
    public int speed = 3;  // 蛇的速度
    public long delay = 800 / speed; // 蛇的移动时间间隔 (暂定 speed * delay == 500)

    public boolean isLive = true; // 蛇是否存活
    public int ateNum = 0; // 蛇吃到的食物数量
    public Vector<Buff> buffs = new Vector<>(); // 蛇所持有的 buff

    public boolean moved = true;//解决蛇快速变向导致意外死亡的问题

    /**
     * 在游戏地图生成蛇
     * @param panel 蛇所在的游戏面板
     * @param row 横坐标
     * @param col 纵坐标
     */
    public Snake(GamePanel panel, int row, int col){
        this.panel = panel;
        // 蛇坐标初始化
        length = 3;
        for (int i = 0; i < length; i++) {
            bodyCol[i] = col;
            bodyRow[i] = row + i;
        }

        // 游戏界面数组变化
        for (int i = 0; i < length; i++) {
            panel.map[row + i][col] = SNAKE_BODY;
        }
        new Thread(this).start();
    }

    /**
     * 带有设定长度和速度的初始化
     */
    public Snake(GamePanel panel, int row, int col, int length,int speed) {
        this.length=length;
        this.speed=speed;
        this.panel = panel;
        // 蛇坐标初始化
        for (int i = 0; i < length; i++) {
            bodyCol[i] = col;
            bodyRow[i] = row + i;
        }

        // 游戏界面数组变化
        for (int i = 0; i < length; i++) {
            panel.map[row + i][col] = SNAKE_BODY;
        }
        this.delay = 500 / this.speed;
        new Thread(this).start();
    }

    /**
     * 蛇的移动
     * - 移动成功后，panel 中 map 数组需要做出相应变化
     */
    public void move() {
        // panel.map 中的旧的蛇尾所占位置赋值为 0
        int tailX = bodyCol[length - 1];
        int tailY = bodyRow[length - 1];
        panel.map[tailY][tailX] = NULL;

        // panel.map 中的旧的蛇头所占位置赋值为 4
        panel.map[bodyRow[0]][bodyCol[0]] = SNAKE_BODY;

        // 蛇身移动
        for (int i = length - 1; i > 0; i--) { // 蛇尾移动
            bodyCol[i] = bodyCol[i - 1];
            bodyRow[i] = bodyRow[i - 1];
        }

        // 蛇头根据当前方向移动
        switch (direction) {
            case UP:
                bodyRow[0]--;
                break;
            case RIGHT:
                bodyCol[0]++;
                break;
            case DOWN:
                bodyRow[0]++;
                break;
            case LEFT:
                bodyCol[0]--;
                break;
        }

        // panel.map 中新的蛇头所占位置赋值为 SNAKE_HEAD
        int headX = bodyCol[0];
        int headY = bodyRow[0];
        panel.map[headY][headX] = SNAKE_HEAD;
    }

    /**
     * 碰撞检测
     * @return true,发生致命碰撞；false,未发生致命碰撞
     */
    public boolean collisionDetection() {
        // 蛇头下一步会移动到的地方位置
        int nextRow = -1, nextCol = -1;
        switch (direction) {
            case UP:
                nextRow = bodyRow[0] - 1;
                nextCol = bodyCol[0];
                break;
            case RIGHT:
                nextRow = bodyRow[0];
                nextCol = bodyCol[0] + 1;
                break;
            case DOWN:
                nextRow = bodyRow[0] + 1;
                nextCol = bodyCol[0];
                break;
            case LEFT:
                nextRow = bodyRow[0];
                nextCol = bodyCol[0] - 1;
                break;
        }

        // 判断地图元素
        switch (panel.map[nextRow][nextCol]) {
            case NULL: // 无元素，不会发生碰撞
            case FOOD: // 食物
                return false;
            case BORDER: // 地图边界
                if (buffs.contains(Buff.SHIELD)) {
                    // 有护盾buff，顺时针拐弯即可，并消除护盾buff
                    turnClockwise();
                    buffs.remove(Buff.SHIELD);
                    return false;
                } else {
                    // 无护盾buff，蛇死亡
                    isLive = false;
                }
                isLive = false;
                break;
            case WALL: // 墙
                if (buffs.contains(Buff.THROUGH_WALL)) {
                    // 有穿墙buff，返回 false ，忽略本次撞击
                    return false;
                } else if (buffs.contains(Buff.SHIELD)) {
                    // 有护盾buff，顺时针拐弯即可，并消除护盾buff
                    turnClockwise();
                    buffs.remove(Buff.SHIELD);
                    return false;
                } else {
                    // 无穿墙和护盾buff，蛇死亡
                    isLive = false;
                }
                break;
            case SNAKE_BODY:
                if (buffs.contains(Buff.SHIELD)) {
                    turnClockwise();
                    buffs.remove(Buff.SHIELD);
                    return false;
                } else {
                    isLive = false;
                }
                break;
        }
        return true;
    }

    /**
     * 顺时针转动
     */
    public void turnClockwise() {
        switch (direction) {
            case UP:
                direction = Direction.RIGHT;
                break;
            case RIGHT:
                direction = Direction.DOWN;
                break;
            case DOWN:
                direction = Direction.LEFT;
                break;
            case LEFT:
                direction = Direction.UP;
                break;
        }
    }

    /**
     * 吃食物检测（在collisionDetection后，move前进行）
     * - 需要完成吃食物后的 length, speed, buff 等属性的变化
     * @return 吃到了，返回true；否则返回false
     */
    public boolean eatingFoodDetection() {
        // 蛇头下一步会移动到的地方位置
        int nextRow = -1, nextCol = -1;
        switch (direction) {
            case UP:
                nextRow = bodyRow[0] - 1;
                nextCol = bodyCol[0];
                break;
            case RIGHT:
                nextRow = bodyRow[0];
                nextCol = bodyCol[0] + 1;
                break;
            case DOWN:
                nextRow = bodyRow[0] + 1;
                nextCol = bodyCol[0];
                break;
            case LEFT:
                nextRow = bodyRow[0];
                nextCol = bodyCol[0] - 1;
                break;
        }

        // 判断是否吃到食物
        for (Food food : panel.foods) {
            if (food.row == nextRow && food.col == nextCol) {
                // 吃到了
                food.isLive = false;
                // 食物从 panel 中剔除
                panel.foods.remove(food);
                panel.map[nextRow][nextCol] = NULL;
                // 分值变化（panel.score）
                panel.score += food.value;

                // 蛇增加一个尾部，bodyX 和 bodyY 需要变化
                bodyRow[length] = bodyRow[length - 1];
                bodyCol[length] = bodyCol[length - 1];
                // 长度加一
                length++;
                // 增加食物所带buff
                if (food.buff != Buff.NORMAL) {
                    applyBuff(food.buff);
                }
                // 由 ateNum 判断是否需要改变 speed 和 delay
                ateNum++;
                if (ateNum == 5) {
                    speed++;
                    delay = 500 / speed;
                    ateNum = 0;
                }

                System.out.println("蛇吃到了食物！");
                return true;
            }
        }
        // 未吃到食物，返回false
        return false;
    }

    /**
     * 增添 buff
     * @param buff
     */
    public void applyBuff(Buff buff) {
        synchronized (buffs) {
            // 设置 buff 开始时间（即游戏运行的时间）
            buff.setBuffStartTime(panel.runTime); // runTime 就是游戏运行的时长
            if (buff == Buff.SPEED_UP) {
                speed += 2;
                delay = 500 / speed;
            }
            buffs.add(buff);
        }
    }

    /**
     * buff 更新
     * - 在每次游戏循环中调用，用于检查Buff是否结束并执行相应的逻辑
     */
    public void updateBuff() {
        synchronized (buffs) {
            // 现在的时间 - 开始 > 持续时间
            Iterator<Buff> it = buffs.iterator();
            while (it.hasNext()) {
                Buff buff = it.next();
                if (panel.runTime - buff.getBuffStartTime() > buff.getDuration()) {
                    if (buff == Buff.SPEED_UP) {
                        speed -= 2;
                        delay = 500 / speed;
                    }
                    it.remove();
                }
            }
        }
    }

    /**
     * 蛇每隔 delay 就进行一次移动
     * - 蛇死亡后结束线程
     */
    @Override
    public void run() {
        while (isLive) {
            if (!panel.isPaused) {
                // 游戏并未暂停且蛇存活
                // 碰撞检检测
                if (!collisionDetection()) {
                    // 吃食物检测
                    eatingFoodDetection();
                    move(); //  蛇的移动都由这个方法执行
                }
                moved = true;
                // 更新蛇的buff
                updateBuff();
            } else {
                // 游戏暂停，什么也不变
            }
            try {
                Thread.sleep(delay);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
